home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
lib
/
c
/
etc
/
option.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-28
|
11KB
|
449 lines
/*
* option.c --
*
* Routines to do command line option processing.
*
* Copyright 1986, 1991 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /sprite/src/lib/c/etc/RCS/option.c,v 1.9 91/01/28 16:44:36 kupfer Exp $ SPRITE (Berkeley)";
#endif not lint
#include <option.h>
#include <cfuncproto.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <time.h>
#define OptNoArg(progName, opt) fprintf(stderr, \
"Warning: %s option \"-%s\" needs an argument\n", \
(progName), (opt))
/* Forward references: */
static void ParseTime _ARGS_ ((char *progName, char *str,
time_t *resultPtr));
/*
*----------------------------------------------------------------------
*
* Opt_Parse --
*
* Process a command line according to a template of accepted
* options. See the manual page and header file for more details.
*
* Results:
* The number of options that weren't processed by this procedure
* is returned, and argv points to an array of unprocessed
* options. (This is all of the options that didn't start with
* "-", except for those used as arguments to the options
* processed here; it's also anything after an OPT_REST option.)
*
* Side effects:
* The variables referenced from the option array get modified
* if their option was present on the command line. Can clobber
* the global buffer used by localtime(3).
*
*----------------------------------------------------------------------
*/
int
Opt_Parse(argc, argv, optionArray, numOptions, flags)
register int argc; /* Number of arguments in argv. */
char **argv; /* Array of arguments */
Option optionArray[]; /* Array of option descriptions */
int numOptions; /* Size of optionArray */
int flags; /* Or'ed combination of various flag bits:
* see option.h for definitions. */
{
register Option *optionPtr; /* pointer to the current option in the
* array of option specifications */
register char *curOpt; /* Current flag argument */
register char **curArg; /* Current argument */
register int argIndex; /* Index into argv to which next unused
* argument should be copied */
int stop=0; /* Set non-zero to stop processing
* arguments when an OPT_REST flag is
* encountered */
int length; /* Number of characters in current
* option. */
argIndex = 1;
argc -= 1;
curArg = &argv[1];
while (argc && !stop) {
if (**curArg == '-') {
curOpt = &curArg[0][1];
curArg += 1;
argc -= 1;
/*
* Check for the special options "?" and "help". If found,
* print documentation and exit.
*/
if ((strcmp(curOpt, "?") == 0) || (strcmp(curOpt, "help") == 0)) {
Opt_PrintUsage (argv[0], optionArray, numOptions);
exit(0);
}
/*
* Loop over all the options specified in a single argument
* (must be 1 unless OPT_ALLOW_CLUSTERING was specified).
*/
while (1) {
/*
* Loop over the array of options searching for one with the
* matching key string. If found, it is left pointed to by
* optionPtr.
*/
for (optionPtr = &optionArray[numOptions - 1];
optionPtr >= optionArray;
optionPtr -= 1) {
if (optionPtr->key == NULL) {
continue;
}
if (*optionPtr->key == *curOpt) {
if (flags & OPT_ALLOW_CLUSTERING) {
length = strlen(optionPtr->key);
if (strncmp(optionPtr->key, curOpt, length) == 0) {
break;
}
} else {
if (strcmp(optionPtr->key, curOpt) == 0) {
break;
}
}
}
}
if (optionPtr < optionArray) {
/*
* No match. Print error message and skip option.
*/
fprintf(stderr, "Unknown option \"-%s\";", curOpt);
fprintf(stderr, " type \"%s -help\" for information\n",
argv[0]);
break;
}
/*
* Take the appropriate action based on the option type
*/
if (optionPtr->type >= 0) {
*((int *) optionPtr->address) = optionPtr->type;
} else {
switch (optionPtr->type) {
case OPT_REST:
stop = 1;
*((int *) optionPtr->address) = argIndex;
break;
case OPT_STRING:
if (argc == 0) {
OptNoArg(argv[0], optionPtr->key);
} else {
*((char **)optionPtr->address) = *curArg;
curArg++;
argc--;
}
break;
case OPT_INT:
if (argc == 0) {
OptNoArg(argv[0], optionPtr->key);
} else {
char *endPtr;
*((int *) optionPtr->address) =
strtol(*curArg, &endPtr, 0);
if (endPtr == *curArg) {
fprintf(stderr,
"Warning: option \"-%s\" got a non-numeric argument \"%s\". Setting to 0.\n",
optionPtr->key, *curArg);
}
curArg++;
argc--;
}
break;
case OPT_TIME:
if (argc == 0) {
OptNoArg(argv[0], optionPtr->key);
} else {
ParseTime(argv[0], *curArg,
(time_t *)optionPtr->address);
curArg++;
argc--;
}
break;
case OPT_FLOAT:
if (argc == 0) {
OptNoArg(argv[0], optionPtr->key);
} else {
char *endPtr;
*((double *) optionPtr->address) =
strtod(*curArg, &endPtr);
if (endPtr == *curArg) {
fprintf(stderr,
"Warning: option \"-%s\" got non-floating-point argument \"%s\". Setting to 0.\n",
optionPtr->key, *curArg);
}
curArg++;
argc--;
}
break;
case OPT_GENFUNC: {
int (*handlerProc)();
handlerProc = (int (*)())optionPtr->address;
argc = (* handlerProc) (optionPtr->key, argc,
curArg);
break;
}
case OPT_FUNC: {
int (*handlerProc)();
handlerProc = (int (*)())optionPtr->address;
if ((* handlerProc) (optionPtr->key, *curArg)) {
curArg += 1;
argc -= 1;
}
break;
}
case OPT_DOC:
Opt_PrintUsage (argv[0], optionArray, numOptions);
exit(0);
/*NOTREACHED*/
}
}
/*
* Advance to next option
*/
if (flags & OPT_ALLOW_CLUSTERING) {
curOpt += length;
if (*curOpt == 0) {
break;
}
} else {
break;
}
}
} else {
/*
* *curArg is an argument for which we have no use, so copy it
* down.
*/
argv[argIndex] = *curArg;
argIndex += 1;
curArg += 1;
argc -= 1;
/*
* If this wasn't an option, and we're supposed to stop parsing
* the first time we see something other than "-", quit.
*/
if (flags & OPT_OPTIONS_FIRST) {
stop = 1;
}
}
}
/*
* If we broke out of the loop because of an OPT_REST argument, we want
* to copy the rest of the arguments down, so we do.
*/
while (argc) {
argv[argIndex] = *curArg;
argIndex += 1;
curArg += 1;
argc -= 1;
}
argv[argIndex] = (char *)NULL;
return argIndex;
}
/*
*----------------------------------------------------------------------
*
* Opt_PrintUsage --
*
* Print out a usage message for a command. This prints out the
* documentation strings associated with each option.
*
* Results:
* none.
*
* Side effects:
* Messages printed onto the console.
*
*----------------------------------------------------------------------
*/
void
Opt_PrintUsage(commandName, optionArray, numOptions)
char *commandName;
Option optionArray[];
int numOptions;
{
register int i;
int width;
/*
* First, compute the width of the widest option key, so that we
* can make everything line up.
*/
width = 4;
for (i=0; i<numOptions; i++) {
int length;
if (optionArray[i].key == NULL) {
continue;
}
length = strlen(optionArray[i].key);
if (length > width) {
width = length;
}
}
fprintf(stderr, "Usage of command \"%s\"\n", commandName);
for (i=0; i<numOptions; i++) {
if (optionArray[i].type != OPT_DOC) {
fprintf(stderr, " -%s%-*s %s\n", optionArray[i].key,
width+1-strlen(optionArray[i].key), ":",
optionArray[i].docMsg);
switch (optionArray[i].type) {
case OPT_INT: {
fprintf(stderr, "\t\tDefault value: %d\n",
*((int *) optionArray[i].address));
break;
}
case OPT_FLOAT: {
fprintf(stderr, "\t\tDefault value: %lg\n",
*((double *) optionArray[i].address));
break;
}
case OPT_STRING: {
if (*(char **)optionArray[i].address != (char *) NULL) {
fprintf(stderr, "\t\tDefault value: \"%s\"\n",
*(char **) optionArray[i].address);
break;
}
}
default: {
break;
}
}
} else {
fprintf(stderr, " %s\n", optionArray[i].docMsg);
}
}
fprintf(stderr, " -help%-*s Print this message\n", width-3, ":");
}
/*
*----------------------------------------------------------------------
*
* ParseTime --
*
* Convert a date and time from some string representation to
* something we can compute with.
*
* Results:
* If str points to a parsable time, the corresponding UNIX time
* value (seconds past the epoch) is returned through resultPtr.
*
* Side effects:
* Can clobber the global buffer used by localtime(3).
*
*----------------------------------------------------------------------
*/
static void
ParseTime(progName, str, resultPtr)
char *progName; /* name that the program was called as */
char *str; /* the string to parse */
time_t *resultPtr; /* pointer to result time value */
{
long result; /* the answer */
char *endPtr; /* pointer into str, for parsing */
struct tm pieces; /* year, month, etc. as integers */
/*
* We currently accept the following formats:
*
* (1) an integer number of seconds past the epoch.
* (2) a string of the form "yy.mm.dd.hh.mm.ss"
*/
result = strtol(str, &endPtr, 0);
if (endPtr == str) {
goto parseError;
}
if (*endPtr == '\0') {
*resultPtr = result;
return;
}
/*
* Not a simple integer, so try form 2.
*/
if (*endPtr != '.') {
goto parseError;
}
pieces.tm_year = result;
if (pieces.tm_year > 1900) {
pieces.tm_year -= 1900;
}
pieces.tm_mon = strtol(endPtr+1, &endPtr, 0) - 1;
if (endPtr == str || *endPtr != '.') {
goto parseError;
}
pieces.tm_mday = strtol(endPtr+1, &endPtr, 0);
if (endPtr == str || *endPtr != '.') {
goto parseError;
}
pieces.tm_hour = strtol(endPtr+1, &endPtr, 0);
if (endPtr == str || *endPtr != '.') {
goto parseError;
}
pieces.tm_min = strtol(endPtr+1, &endPtr, 0);
if (endPtr == str || *endPtr != '.') {
goto parseError;
}
pieces.tm_sec = strtol(endPtr+1, &endPtr, 0);
if (endPtr == str || *endPtr != '\0') {
goto parseError;
}
result = mktime(&pieces);
if (result == -1) {
fprintf(stderr, "%s: can't represent the time \"%s\".\n",
progName, str);
} else {
*resultPtr = result;
}
return;
parseError:
fprintf(stderr, "%s: can't parse \"%s\" as a time.\n", progName, str);
return;
}